﻿/// <reference path="http://www.microsoft.com/resources/ajax/jquery/jquery-1.4.2-vsdoc.js" />

/*
Entities are sent from the server using the GeoJSON format. See
http://geojson.org/geojson-spec.html
*/

var MainPage = {
    // IMPORTANT: put your Bing Maps credentials here
    credentials: "My Bing Map Credentials",
    currentTabIndex: 0,
    controlsWidth: 360,

    Initialize: function () {

        // This simple error handling displays the Error page produced by default.
        // In production you would obviously want something better.
        $.ajaxSetup({
            error: function (err, y) {
                alert("ajax error");
                $("#ErrorPage").html(err.responseText);
            }
        });

        // show a message during ajax loading
        $("body").ajaxStart(MainPage.ShowLoading);

        // hide it when all ajax traffic is finished
        $("body").ajaxStop(MainPage.HideLoading);

        // The tab HTML is delivered by ajax. We need to connect callbacks to the HTML elements
        // when they are created.
        $("#MainPageTabs").tabs({
            cache: true,

            load: function (event, ui) {
                switch (ui.index) {
                    case 0:
                        GettingStarted.Initialize();
                        break;

                    case 1:
                        DrawingPage.Initialize(ui);
                        break;

                    case 2:
                        Tiling.Initialize(ui);
                        break;

                    case 3:
                        Hybrid.Initialize(ui);
                        break;
                }
            },

            show: function (event, ui) {
                MainPage.currentTabIndex = ui.index;

                switch (ui.index) {
                    case 0:
                        Tiling.Unshow();
                        DrawingPage.Unshow();
                        Hybrid.Unshow();
                        GettingStarted.Show();
                        break;

                    case 1:
                        GettingStarted.Unshow();
                        Tiling.Unshow();
                        Hybrid.Unshow();
                        DrawingPage.Show();
                        break;

                    case 2:
                        GettingStarted.Unshow();
                        DrawingPage.Unshow();
                        Hybrid.Unshow();
                        Tiling.Show();
                        break;

                    case 3:
                        GettingStarted.Unshow();
                        DrawingPage.Unshow();
                        Tiling.Unshow();
                        Hybrid.Show();
                        break;
                }
            }
        });
        /*
        // Loading and NoDataFound dialogs are common
        $("#Loading").dialog({
        autoOpen: false,
        resizable: false
        });
        */
        $("#NoDataFound").dialog({
            autoOpen: false,
            title: "No Items Found"
        });

    },

    GoToDrawing: function () {
        $("#MainPageTabs").tabs("select", 1);
    },

    GoToTiling: function () {
        $("#MainPageTabs").tabs("select", 2);
    },

    GoToHybrid: function () {
        $("#MainPageTabs").tabs("select", 3);
    },
    
    ShowLoading: function () {
        $("#Loading").show();
        $mover = $("#Loading .load_mover");
        var goleft = function () {
            $mover.animate({ left: 20 }, 3000, "linear", goright);
        };

        var goright = function () {
            $mover.animate({ left: 180 }, 3000, "linear", goleft);
        };
        $mover.css({ left: 20 });
        goright();
    },

    HideLoading: function () {
        $("#Loading").hide();
        $("#Loading .load_mover").stop();
    },

    ShowNoDataFound: function () {
        $("#NoDataFound").dialog("open");
    },

    HideNoDataFound: function () {
        $("#NoDataFound").dialog("close");
    }
};

// The methods and data in this object handle GettingStarted.ascx
var GettingStarted = {
    Initialize: function () {
    },

    // show a source file in a dialog
    // The ShowSourceAsHtml will turn a given source file into HTML.
    ShowSource: function (path) {
        $("#CodePage").load("/Home/ShowSourceAsHtml", "file=" + path, function () {
            $(this).dialog({
                title: path,
                width: $(window).width() - 100,
                height: $(window).height() - 100
            });
        });
        return undefined; // prevent link following
    },

    Show: function () {
    },

    Unshow: function () {
        $("#CodePage").dialog("close");
    }
};


// The methods and data in this object handle Drawing.ascx
var DrawingPage = {

    // the map
    map: null,

    // entities being displayed
    userEntities: null,
    displayEntities: null,

    // latest set of data from server
    currentData: {},

    // time in millies when data received
    currentDataTime: 0,

    // time in millies when data requested
    ajaxRequestTime: 0,

    // size in bytes of the last message
    ajaxResponseSize: 0,

    // current user input
    queryType: "Proximity",
    inputFinished: false,
    pointLocations: [],

    // map entity drawing options
    inputLineOptions: {
        strokeColor: new Microsoft.Maps.Color(128, 100, 255, 100),
        strokeWidth: 5
    },

    inputPolygonOptions: {
        strokeColor: new Microsoft.Maps.Color(128, 100, 255, 100),
        strokeWidth: 5,
        fillColor: new Microsoft.Maps.Color(25, 100, 100, 255)
    },

    earthquakePushpinOptions: {
        visible: true,
        anchor: new Microsoft.Maps.Point(7, 7),
        width: 15,
        height: 15,
        icon: "/Content/Images/small_yellow_circle.png"
    },

    faultPolylineOptions: {
        strokeColor: new Microsoft.Maps.Color(255, 255, 0, 0),
        strokeWidth: 2
    },

    countryPolygonOptions: {
        strokeColor: new Microsoft.Maps.Color(128, 255, 100, 100),
        strokeWidth: 3,
        fillColor: new Microsoft.Maps.Color(25, 100, 100, 255)
    },

    countyPolygonOptions: {
        strokeColor: new Microsoft.Maps.Color(128, 255, 100, 100),
        strokeWidth: 3,
        fillColor: new Microsoft.Maps.Color(25, 100, 100, 255)
    },

    statePolygonOptions: {
        strokeColor: new Microsoft.Maps.Color(128, 255, 100, 100),
        strokeWidth: 3,
        fillColor: new Microsoft.Maps.Color(25, 100, 100, 255)
    },

    inputLocationPushpinOptions: {
        visible: true,
        anchor: new Microsoft.Maps.Point(12, 12),
        width: 25,
        height: 25,
        icon: "/Content/Images/red_crosshairs.png"
    },

    // This will hook up elements on the Drawing.ascx "page" when
    // it is loaded.
    Initialize: function (ui) {
        var $panel = $("#ControlPanel", ui.panel);

        // ControlPanel will be a modeless dialog
        $panel.dialog({
            title: "Controls",
            minWidth: MainPage.controlsWidth,
            maxWidth: MainPage.controlsWidth,
            autoOpen: true,
            resizable: true,
            height: $(window).height() - 100,
            position: ['right', 'bottom']
        });

        // create explanation dialog
        $("#Instructions").dialog({
            title: "Instructions - Vector Data",
            autoOpen: true,
            resizable: true,
            height: $(window).height() - 150,
            position: ['left']
        });

        $("#ShowInstructions")
            .button()
            .click(function () { $("#Instructions").dialog("open"); });

        $(".panel", $panel)
            .accordion({
                collapsible: true,
                header: 'h3'
            });

        $(".opacity_slider", $panel)
            .slider({
                min: 0,
                max: 255
            });

        $("#DistanceSlider", $panel)
            .slider({
                min: 1,
                max: 200,
                slide: function (e, ui) {
                    $("#DistanceText").text(ui.value);
                },
                change: function (e, ui) {
                    $("#DistanceText").text(ui.value);
                }
            });

        $("#QueryButton", $panel)
            .button()
            .click(function (e) {
                // serialize query and send it to server
                DrawingPage.SendQuery($panel);
                e.preventDefault();
            });

        $("#ResetButton", $panel)
            .button()
            .click(function (e) {
                // reset controls
                DrawingPage.Reset($panel);
                e.preventDefault();
            });

        $("#RedrawButton", $panel)
            .button()
            .hide()
            .click(function (e) {
                // render entities
                DrawingPage.Render();
                e.preventDefault();
            });

        $("input[name='QueryType']", $panel)
            .click(function (e) {
                DrawingPage.QueryTypeChanged($panel);
            });


        $("#ShowControlPanel")
            .button()
            .click(function () { $panel.dialog("open"); });

        // Create map.
        var mapOptions = {
            credentials: MainPage.credentials,
            center: new Microsoft.Maps.Location(40, -105),
            mapTypeId: Microsoft.Maps.MapTypeId.birdseye,
            zoom: 5,
            showScalebar: true
        };

        var mm = Microsoft.Maps;
        DrawingPage.map = new mm.Map(document.getElementById("Map"), mapOptions);
        DrawingPage.userEntities = new mm.EntityCollection();
        DrawingPage.map.entities.push(DrawingPage.userEntities);
        DrawingPage.displayEntities = new mm.EntityCollection();
        DrawingPage.map.entities.push(DrawingPage.displayEntities);

        // we use mouse clicks
        mm.Events.addHandler(DrawingPage.map, "click", DrawingPage.MouseClicked);
        mm.Events.addHandler(DrawingPage.map, "dblclick", DrawingPage.MouseDoubleClicked);

        // we track mouse movement for demonstration purposes
        mm.Events.addHandler(DrawingPage.map, "mousemove", DrawingPage.MouseMoved);

        // set the control panel defaults
        DrawingPage.Reset($panel);

        $(window).resize(DrawingPage.ResizeMap);

        DrawingPage.Show();
    },

    // restore default control state
    Reset: function (panel) {
        $panel = $(panel);

        // opacity sliders get reset to 50%
        $(".opacity_slider", $panel).each(function (index, el) {
            $(this).slider("value", 128);
        });

        // distance slider reset to 25KM
        $("#DistanceSlider", $panel)
            .slider("value", 25);

        // uncheck all Show checkboxes
        $("#ShowItems input:checked", $panel).removeAttr("checked");

        // set Proximity as the query type
        $("input[name='QueryType'][value='Proximity']", $panel).click();
    },

    // This is a map callback.
    // The callback argument is a Microsoft.Maps.MouseEventArgs
    MouseMoved: function (e) {
        var mm = Microsoft.Maps;
        var location = DrawingPage.map.tryPixelToLocation(new mm.Point(e.pageX, e.pageY), mm.PixelReference.page);
        if (location == null || isNaN(location.latitude) || isNaN(location.longitude)) {
            return;
        }

        var $panel = $("#CurrentView");
        $("#CurrentViewLatitude", $panel).text(location.latitude.toFixed(8));
        $("#CurrentViewLongitude", $panel).text(location.longitude.toFixed(8));
        $("#CurrentViewZoom", $panel).text(DrawingPage.map.getZoom().toFixed(0));
    },

    // Build up a user input object, of a type depending on the current queryType.
    // Viewport: none
    // Proximity: single Point
    // Line: LineString
    // Area: Polygon
    // 
    // This is a map callback.
    // The callback argument is a Microsoft.Maps.MouseEventArgs
    MouseClicked: function (e) {
        var mm = Microsoft.Maps;
        var location = DrawingPage.map.tryPixelToLocation(new mm.Point(e.pageX, e.pageY), mm.PixelReference.page);
        if (location == null || isNaN(location.latitude) || isNaN(location.longitude)) {
            return;
        }

        switch (DrawingPage.queryType) {
            case "Proximity":
                DrawingPage.userEntities.clear();
                var pp = new mm.Pushpin(location, DrawingPage.inputLocationPushpinOptions);
                DrawingPage.userEntities.push(pp);

                DrawingPage.pointLocations = [location];

                // we are finished with input
                DrawingPage.inputFinished = true;
                break;

            case "Line":
                if (DrawingPage.inputFinished) {
                    return;
                }
                DrawingPage.pointLocations.push(location);

                var m = new mm.Pushpin(location, DrawingPage.inputLocationPushpinOptions);
                DrawingPage.userEntities.push(m);

                if (DrawingPage.pointLocations.length >= 2) {
                    var line = new mm.Polyline(DrawingPage.pointLocations, DrawingPage.inputLineOptions);
                    DrawingPage.userEntities.push(line);
                }
                break;

            case "Area":
                if (DrawingPage.inputFinished) {
                    return;
                }
                DrawingPage.pointLocations.push(location);
                var c = new mm.Pushpin(location, DrawingPage.inputLocationPushpinOptions);
                DrawingPage.userEntities.push(c);

                if (DrawingPage.pointLocations.length >= 2) {
                    var circ = new mm.Polyline(DrawingPage.pointLocations, DrawingPage.inputLineOptions);
                    DrawingPage.userEntities.push(circ);
                }
                break;
        }
    },



    // Finish up a user input object, of a type depending on the QueryType.
    // Viewport: none (ignore)
    // Proximity: single Point (ignore)
    // Line: LineString
    // Area: Polygon  
    // 
    // This is a map callback.
    // The callback argument is a Microsoft.Maps.MouseEventArgs  
    MouseDoubleClicked: function (e) {
        if (DrawingPage.inputFinished) {
            return;
        }
        var mm = Microsoft.Maps;
        var location = DrawingPage.map.tryPixelToLocation(new mm.Point(e.pageX, e.pageY), mm.PixelReference.page);
        if (location == null || isNaN(location.latitude) || isNaN(location.longitude)) {
            return;
        }

        // a point may already have been pushed, so we check for dups
        var pl = DrawingPage.pointLocations;
        var dup = (pl.length > 0) && mm.Point.areEqual(pl[pl.length - 1], location);

        // ignore Proximity and Viewport
        switch (DrawingPage.queryType) {
            case "Line":
                if (!dup) {
                    DrawingPage.pointLocations.push(location);
                }

                DrawingPage.userEntities.clear();
                var line = new mm.Polyline(DrawingPage.pointLocations, DrawingPage.inputLineOptions);
                DrawingPage.userEntities.push(line);
                break;

            case "Area":
                if (!dup) {
                    DrawingPage.pointLocations.push(location);
                }
                DrawingPage.pointLocations.push(DrawingPage.pointLocations[0]);
                DrawingPage.userEntities.clear();
                var polygon = new mm.Polygon(DrawingPage.pointLocations, DrawingPage.inputPolygonOptions);
                DrawingPage.userEntities.push(polygon);
                break;
        }

        // we are finished with input
        DrawingPage.inputFinished = true;

        // prevent map from moving
        e.handled = true;
    },

    // Start a new query user interaction.
    // Clear map and start UI in the current mode.
    QueryTypeChanged: function (panel) {
        var $panel = $(panel);
        DrawingPage.queryType = $("input[name='QueryType']:checked", $panel).val();

        // clear map entities
        DrawingPage.userEntities.clear();
        DrawingPage.displayEntities.clear();

        // clear user input
        DrawingPage.pointLocations = [];

        // in Viewport mode, no input is needed
        DrawingPage.inputFinished = (DrawingPage.queryType == "Viewport");
    },

    // jquery ajax completion
    // save data
    // alert on error
    // redraw data
    ReceiveData: function (data, status, xhr) {
        DrawingPage.currentData = data;
        DrawingPage.currentDataTime = (new Date()).getTime();
        DrawingPage.ajaxResponseSize = xhr.responseText.length;

        if (data.error) {
            alert(data.error);
            return;
        }

        DrawingPage.Render();

        if (data.metrics.NumberOfPoints == 0) {
            MainPage.ShowNoDataFound();
        }
    },

    // redraw entities on the map
    Render: function () {
        DrawingPage.displayEntities.clear();
        var data = DrawingPage.currentData;
        if (!data || !data["featureSet"]) {
            return;
        }
        var start = (new Date()).getTime();
        DrawingPage.DrawCountries(data.featureSet["Countries"]);
        DrawingPage.DrawStates(data.featureSet["States"]);
        DrawingPage.DrawCounties(data.featureSet["Counties"]);
        DrawingPage.DrawFaults(data.featureSet["Faults"]);
        DrawingPage.DrawEarthquakes(data.featureSet["Earthquakes"]);

        // calculate times
        var render = (new Date()).getTime() - start;
        var request = DrawingPage.currentDataTime - DrawingPage.ajaxRequestTime;
        var transmit = request - data.metrics.QueryTimeMilliseconds;
        var total = request + render;

        var $metrics = $("#Metrics");
        $("#MetricsNumberOfFeatures", $metrics).text(data.metrics.NumberOfFeatures);
        $("#MetricsNumberOfPoints", $metrics).text(data.metrics.NumberOfPoints);
        $("#MetricsResponseSize", $metrics).text(DrawingPage.ajaxResponseSize);
        $("#MetricsTotalLoadTime", $metrics).text(total + "ms");
        $("#MetricsQueryTimeMilliseconds", $metrics).text(data.metrics.QueryTimeMilliseconds + "ms");
        $("#MetricsTransmitTime", $metrics).text(transmit + "ms");
        $("#MetricsRenderTime", $metrics).text(render + "ms");
    },

    // convenience function to get opacity value from a slider 
    GetOpacity: function (name) {
        var opacity = $("#ShowItems input[name='" + name + "']").closest(".item_row").find(".opacity_slider").slider("value");
        opacity = parseInt(opacity);
        if (opacity < 0)
            opacity = 0;
        else if (opacity > 255)
            opacity = 255;
        return opacity;
    },

    // Draw Countries.
    // Countries are drawn as filled polygons.
    // Bing Map SDK only draws simple polygons (no holes), so we only draw the exterior ring.
    // According to the GeoJSON standard, feature.geometry.coordinates is an array of polygons.
    DrawCountries: function (countries) {
        if (countries) {
            // get opacity from slider
            DrawingPage.countryPolygonOptions.fillColor.a = DrawingPage.GetOpacity("Countries");

            var mm = Microsoft.Maps;
            for (var i = 0; i < countries.features.length; i++) {
                var feature = countries.features[i];
                var geometry = feature.geometry;
                var properties = feature.properties;
                $.each(geometry.coordinates, function (index, poly) {
                    // draw only the first (exterior) polygon
                    var locations = [];
                    $.each(poly[0], function (cindex, coord) {
                        var location = new mm.Location(coord[0], coord[1]);
                        locations.push(location);
                    });

                    var polygon = new mm.Polygon(locations, DrawingPage.countryPolygonOptions);

                    polygon["feature"] = feature;
                    mm.Events.addHandler(polygon, "mouseover", DrawingPage.ItemMouseover);
                    mm.Events.addHandler(polygon, "mouseout", DrawingPage.ItemMouseout);

                    DrawingPage.displayEntities.push(polygon);
                });
            }
        }
    },


    // Draw Counties.
    // Counties are drawn as filled polygons.
    // Bing Map SDK only draws simple polygons (no holes), so we only draw the exterior ring.
    // According to the GeoJSON standard, feature.geometry.coordinates is an array of polygons.
    DrawCounties: function (counties) {
        if (counties) {
            // get opacity from slider
            DrawingPage.countyPolygonOptions.fillColor.a = DrawingPage.GetOpacity("Counties");

            var mm = Microsoft.Maps;
            for (var i = 0; i < counties.features.length; i++) {
                var feature = counties.features[i];
                var geometry = feature.geometry;
                var properties = feature.properties;
                $.each(geometry.coordinates, function (index, poly) {
                    // draw only the first (exterior) polygon
                    var locations = [];
                    $.each(poly[0], function (cindex, coord) {
                        var location = new mm.Location(coord[0], coord[1]);
                        locations.push(location);
                    });
                    var polygon = new mm.Polygon(locations, DrawingPage.countyPolygonOptions);

                    polygon["feature"] = feature;
                    mm.Events.addHandler(polygon, "mouseover", DrawingPage.ItemMouseover);
                    mm.Events.addHandler(polygon, "mouseout", DrawingPage.ItemMouseout);

                    DrawingPage.displayEntities.push(polygon);
                });
            }
        }
    },

    // Draw States.
    // States are drawn as filled polygons.
    // Bing Map SDK only draws simple polygons (no holes), so we only draw the exterior ring.
    // According to the GeoJSON standard, feature.geometry.coordinates is an array of polygons.
    DrawStates: function (states) {
        if (states) {
            // get opacity from slider
            DrawingPage.statePolygonOptions.fillColor.a = DrawingPage.GetOpacity("States");

            var mm = Microsoft.Maps;
            for (var i = 0; i < states.features.length; i++) {
                var feature = states.features[i];
                var geometry = feature.geometry;
                var properties = feature.properties;
                $.each(geometry.coordinates, function (index, poly) {
                    // draw only the first (exterior) polygon
                    var locations = [];
                    $.each(poly[0], function (cindex, coord) {
                        var location = new mm.Location(coord[0], coord[1]);
                        locations.push(location);
                    });
                    var polygon = new mm.Polygon(locations, DrawingPage.statePolygonOptions);

                    polygon["feature"] = feature;
                    mm.Events.addHandler(polygon, "mouseover", DrawingPage.ItemMouseover);
                    mm.Events.addHandler(polygon, "mouseout", DrawingPage.ItemMouseout);

                    DrawingPage.displayEntities.push(polygon);
                });
            }
        }
    },

    // Draw Earthquakes using pushpins.
    // According to the GeoJSON standard, feature.geometry.coordinates is an array [latitude, longitude].
    DrawEarthquakes: function (earthquakes) {
        if (earthquakes) {
            var mm = Microsoft.Maps;
            for (var i = 0; i < earthquakes.features.length; i++) {
                var feature = earthquakes.features[i];
                var geometry = feature.geometry;
                var properties = feature.properties;
                var location = new mm.Location(geometry.coordinates[0], geometry.coordinates[1]);
                var pp = new mm.Pushpin(location, DrawingPage.earthquakePushpinOptions);

                pp["feature"] = feature;
                mm.Events.addHandler(pp, "mouseover", DrawingPage.ItemMouseover);
                mm.Events.addHandler(pp, "mouseout", DrawingPage.ItemMouseout);

                DrawingPage.displayEntities.push(pp);
            }
        }
    },

    // Draw Faults as Polylines
    // According to the GeoJSON standard, feature.geometry.coordinates is an array of lines
    DrawFaults: function (faults) {
        if (faults) {
            // get opacity from slider
            DrawingPage.faultPolylineOptions.strokeColor.a = DrawingPage.GetOpacity("Faults");

            var mm = Microsoft.Maps;
            for (var i = 0; i < faults.features.length; i++) {
                var feature = faults.features[i];
                var geometry = feature.geometry;
                var properties = feature.properties;
                $.each(geometry.coordinates, function (index, jline) {
                    var locations = [];
                    $.each(jline, function (lindex, coord) {
                        var location = new mm.Location(coord[0], coord[1]);
                        locations.push(location);
                    });
                    var line = new mm.Polyline(locations, DrawingPage.faultPolylineOptions);

                    // add feature as expando data to the item for use by the mouseover callback
                    line["feature"] = feature;
                    mm.Events.addHandler(line, "mouseover", DrawingPage.ItemMouseover);
                    mm.Events.addHandler(line, "mouseout", DrawingPage.ItemMouseout);

                    DrawingPage.displayEntities.push(line);
                });
            }
        }
    },

    // Show item properties when the mouse hovers over it.
    // 
    // This is a map callback.
    // The callback argument is a Microsoft.Maps.MouseEventArgs  
    ItemMouseover: function (mea) {
        var $props = $("#ItemProperties");
        $("tbody tr", $props).remove();
        var properties = mea.target.feature.properties;
        $.each(properties, function (key, value) {
            var row = $('<tr><td>' + key + '</td><td>' + value + '</td></tr>');
            $("tbody", $props).append(row);
        });

        // calculate a position for the panel
        var loc = $("#MapPanel").position();
        var top = mea.pageY + 10 - loc.top;
        var left = mea.pageX + 10 - loc.left;
        $props.css({ top: top, left: left });
        $props.show();
    },

    // Clear the properties display when the mouse leaves it.
    // 
    // This is a map callback.
    // The callback argument is a Microsoft.Maps.MouseEventArgs  
    ItemMouseout: function (mea) {
        var $props = $("#ItemProperties");
        $props.hide();
    },

    // Send a query for data using the settings from the #ControlPanel elements.
    // N.B. an alternative would be to send JSON
    // Different query types use different URLs and arguments - but it starts here.
    SendQuery: function (panel) {
        // hide dialog if it is left over
        MainPage.HideNoDataFound();
        DrawingPage.ItemMouseout();

        // save time for metrics display
        DrawingPage.ajaxRequestTime = (new Date()).getTime();

        // clear map
        DrawingPage.displayEntities.clear();

        // Get user inputs
        var $panel = $(panel);

        // make CSV of checked tables
        var tables = [];
        $("#ShowItems input:checked", $panel).each(function (index, el) {
            tables.push($(this).attr("name"));
        });

        if (tables.length < 1) {
            alert("Please choose some tables to show.");
            return;
        }

        // Get the bounding box of the map
        var view = DrawingPage.map.getBounds();

        // Every query has bounding box and set of tables
        var query = DrawingPage.MakeViewportQuery(tables, view);

        // we may need the distance
        var distance = $("#DistanceSlider", $panel).slider("value");
        distance = parseInt(distance) * 1000;

        switch (DrawingPage.queryType) {
            case 'Area':
                if (!DrawingPage.inputFinished) {
                    alert("Your Area of Interest has not been finished. Double-click on the map to finish it before clicking Query.");
                    return;
                }
                DrawingPage.SendAreaQuery(panel, query);
                break;

            case 'Line':
                if (!DrawingPage.inputFinished) {
                    alert("Your Line Buffer has not been finished. Double-click on the map to finish it before clicking Query.");
                    return;
                }
                DrawingPage.SendLineQuery(panel, query, distance);
                break;

            case 'Proximity':
                if (!DrawingPage.inputFinished) {
                    alert("Please click on the map to place a Point before clicking Query.");
                    return;
                }
                DrawingPage.SendProximityQuery(panel, query, distance);
                break;

            case 'Viewport':
                DrawingPage.SendViewportQuery(panel, query);
                break;
        }
    },

    // Create a query object using the current viewport and the tables
    MakeViewportQuery: function (tables, view) {
        var data = {
            "box.North": view.getNorth(),
            "box.South": view.getSouth(),
            "box.East": view.getEast(),
            "box.West": view.getWest()
        };
        $.each(tables, function (i, t) {
            data["tables[" + i + "]"] = t;
        });

        return data;
    },

    SendViewportQuery: function (panel, query) {
        $.ajax({
            data: query,
            cache: false,
            success: DrawingPage.ReceiveData,
            type: "POST",
            dataType: "json",
            url: "/Data/GetData"
        });
    },

    SendProximityQuery: function (panel, query, distance) {
        var location = DrawingPage.pointLocations[0];
        var stuff = {
            "point.type": "Point",
            "point.coordinates[0]": location.latitude,
            "point.coordinates[1]": location.longitude,
            "distance": distance
        };
        $.extend(stuff, query);
        var data = $.param(stuff);
        $.ajax({
            data: data,
            cache: false,
            success: DrawingPage.ReceiveData,
            type: "POST",
            dataType: "json",
            url: "/Data/GetDataProximity"
        });
    },

    SendLineQuery: function (panel, query, distance) {
        var stuff = {
            "distance": distance,
            "line.type": "LineString"
        };
        for (var i = 0; i < DrawingPage.pointLocations.length; i++) {
            var location = DrawingPage.pointLocations[i];
            stuff["line.coordinates[" + i + "][0]"] = location.latitude;
            stuff["line.coordinates[" + i + "][1]"] = location.longitude;
        }
        $.extend(stuff, query);
        var data = $.param(stuff);
        $.ajax({
            data: data,
            cache: false,
            success: DrawingPage.ReceiveData,
            type: "POST",
            dataType: "json",
            url: "/Data/GetDataLine"
        });
    },

    SendAreaQuery: function (panel, query) {
        var stuff = {
            "area.type": "Polygon"
        };
        for (var i = 0; i < DrawingPage.pointLocations.length; i++) {
            var location = DrawingPage.pointLocations[i];
            stuff["area.coordinates[0][" + i + "][0]"] = location.latitude;
            stuff["area.coordinates[0][" + i + "][1]"] = location.longitude;
        }
        $.extend(stuff, query);
        var data = $.param(stuff);
        $.ajax({
            data: data,
            cache: false,
            success: DrawingPage.ReceiveData,
            type: "POST",
            dataType: "json",
            url: "/Data/GetDataArea"
        });
    },

    // this is called before initialize, so we bail if initialize has not been called
    Show: function () {
        if (DrawingPage.map == null) {
            return;
        }

        $("#Instructions").dialog("open");
        $("#ControlPanel").dialog("open");

        DrawingPage.ResizeMap();
    },

    ResizeMap: function () {
        if (DrawingPage.map == null) {
            return;
        }
        if (MainPage.currentTabIndex != 1) {
            return;
        }
        // the available height is window height - container height + current map height
        // the container has set its width properly so we just use it
        var height = $(window).height() - $("body").height() + DrawingPage.map.getHeight();
        DrawingPage.map.setOptions({
            height: height,
            width: $("#MapPanel").width()
        });
    },

    Unshow: function () {
        $("#Instructions").dialog("close");
        $("#ControlPanel").dialog("close");
    }
};


// The methods and data in this object handle Tiling.ascx
var Tiling = {

    // the map
    map: null,

    // This will hook up elements on the Tilng.ascx "page" when
    // it is loaded.
    Initialize: function (ui) {
        var $panel = $("#ControlPanel2", ui.panel);

        $panel.dialog({
            title: "Controls",
            minWidth: MainPage.controlsWidth,
            maxWidth: MainPage.controlsWidth,
            autoOpen: true,
            resizable: true,
            height: $(window).height() - 100,
            position: ['right', 'bottom']
        });

        // create explanation dialog
        $("#Instructions2").dialog({
            title: "Instructions - Tiling ",
            autoOpen: true,
            resizable: true,
            position: ['left']
        });

        $("#ShowInstructions2")
            .button()
            .click(function () { $("#Instructions2").dialog("open"); });

        $("#ShowControlPanel2")
            .button()
            .click(function () { $panel.dialog("open"); });

        $(".panel", $panel)
        .accordion({
            collapsible: true,
            header: 'h3'
        });

        $(".opacity_slider", $panel)
            .slider({
                min: 0,
                max: 100,
                value: 50,
                change: Tiling.OpacitySliderChanged
            });

        $("input[type='checkbox']", $panel)
            .click(Tiling.ChangeLayers);

        // create map
        var mm = Microsoft.Maps;
        var mapOptions = {
            credentials: MainPage.credentials,
            center: new mm.Location(40, -105),
            mapTypeId: mm.MapTypeId.birdseye,
            zoom: 5,
            showScalebar: true,
            width: 300,
            height: 300
        };

        Tiling.map = new mm.Map(document.getElementById("Map2"), mapOptions);
        Tiling.ChangeLayers();

        $(window).resize(Tiling.ResizeMap);

        Tiling.Show();

        // we track mouse movement for demonstration purposes
        mm.Events.addHandler(Tiling.map, "mousemove", Tiling.MouseMoved);
    },

    // This is a map callback.
    // The callback argument is a Microsoft.Maps.MouseEventArgs
    MouseMoved: function (e) {
        var mm = Microsoft.Maps;
        var location = Tiling.map.tryPixelToLocation(new mm.Point(e.pageX, e.pageY), mm.PixelReference.page);
        if (location == null || isNaN(location.latitude) || isNaN(location.longitude)) {
            return;
        }

        var $panel = $("#CurrentView2");
        $("#CurrentView2Latitude", $panel).text(location.latitude.toFixed(8));
        $("#CurrentView2Longitude", $panel).text(location.longitude.toFixed(8));
        $("#CurrentView2Zoom", $panel).text(Tiling.map.getZoom().toFixed(0));
    },

    // For a given control div, make a TileLayer.
    // The name comes from the checkbox attribute.
    // The opacity comes from the slider.
    MakeTilingLayer: function (name, opacity, useThematic) {
        var mm = Microsoft.Maps;

        // Create the tile layer source
        var tileSource = new mm.TileSource({
            uriConstructor: '/Tile/Get?layer=' + name + '&quadkey={quadkey}&thematic=' + useThematic.toString()
        });

        // Create the layer
        var layer = new mm.TileLayer({ mercator: tileSource, opacity: opacity });
        return layer;
    },

    // jquery callback, invoked when the slider value has changed
    // We really can't do anything to a layer except create it again, so to change opacity we remove
    // the layer and add back a new layer with the new opacity.
    // Here we use a shotgun (we do them all), but you could replace this particular layer.
    OpacitySliderChanged: function () {
        // HACK! just call ChangeLayers
        Tiling.ChangeLayers();
    },

    // jquery callback, invoked when a checkbox changes
    // Clear the layers, then add in the checked layers.
    ChangeLayers: function () {
        var mm = Microsoft.Maps;
        var $panel = $("#ControlPanel2");

        // remove all layers from map
        Tiling.map.entities.clear();

        // show the color legend for the display type
        var useThematic = $("input[type='checkbox'][name='ThematicCheckbox']", $panel).is(":checked");
        if (useThematic) {
            $("#ThematicLegend", $panel).show();
            $("#Legend", $panel).hide();
        } else {
            $("#ThematicLegend", $panel).hide();
            $("#Legend", $panel).show();
        }

        // add back the selected layers
        // use the opacity from the associated slider
        $("#ShowItems2 input[type='checkbox']:checked", $panel)
            .each(function () {
                var name = $(this).attr("name");
                var opacity = $(this).closest(".item_row").find(".opacity_slider").slider("value");
                opacity = parseFloat(opacity) / 100;
                Tiling.map.entities.push(Tiling.MakeTilingLayer(name, opacity, useThematic));
            });
    },

    // this is called before initialize, so we bail if initialize has not been called
    Show: function () {
        if (Tiling.map == null) {
            return;
        }

        $("#Instructions2").dialog("open");
        $("#ControlPanel2").dialog("open");

        Tiling.ResizeMap();
    },

    ResizeMap: function () {
        if (Tiling.map == null) {
            return;
        }
        if (MainPage.currentTabIndex != 2) {
            return;
        }

        // the available height is window height - container height + current map height
        // the container has set its width properly so we just use it
        var height = $(window).height() - $("body").height() + Tiling.map.getHeight();
        Tiling.map.setOptions({
            height: height,
            width: $("#MapPanel2").width()
        });
    },

    Unshow: function () {
        $("#Instructions2").dialog("close");
        $("#ControlPanel2").dialog("close");
    }

};


// The methods and data in this object handle Hybrid.ascx
var Hybrid = {

    // the map
    map: null,

    // entities being displayed
    layerEntities: null,
    itemEntities: null,

    // graphics options for objects on the map
    earthquakePushpinOptions: {
        visible: true,
        anchor: new Microsoft.Maps.Point(7, 7),
        width: 15,
        height: 15,
        icon: "/Content/Images/small_yellow_circle.png"
    },

    faultPolylineOptions: {
        strokeColor: new Microsoft.Maps.Color(255, 255, 0, 0),
        strokeWidth: 2
    },

    countryPolygonOptions: {
        strokeColor: new Microsoft.Maps.Color(128, 255, 100, 100),
        strokeWidth: 3,
        fillColor: new Microsoft.Maps.Color(25, 100, 100, 255)
    },

    countyPolygonOptions: {
        strokeColor: new Microsoft.Maps.Color(128, 255, 100, 100),
        strokeWidth: 3,
        fillColor: new Microsoft.Maps.Color(25, 100, 100, 255)
    },

    statePolygonOptions: {
        strokeColor: new Microsoft.Maps.Color(128, 255, 100, 100),
        strokeWidth: 3,
        fillColor: new Microsoft.Maps.Color(25, 100, 100, 255)
    },


    // This will hook up elements on the Hybrid.ascx "page" when
    // it is loaded.
    Initialize: function (ui) {
        var $panel = $("#ControlPanel3", ui.panel);

        $panel.dialog({
            title: "Controls",
            minWidth: MainPage.controlsWidth,
            maxWidth: MainPage.controlsWidth,
            autoOpen: true,
            resizable: true,
            height: $(window).height() - 100,
            position: ['right', 'bottom']
        });

        $("#ShowControlPanel3")
            .button()
            .click(function () { $panel.dialog("open"); });

        // create explanation dialog
        $("#Instructions3").dialog({
            title: "Instructions - Hybrid Map",
            autoOpen: true,
            resizable: true,
            position: ['left']
        });

        $("#ShowInstructions3")
            .button()
            .click(function () { $("#Instructions3").dialog("open"); });

        $(".panel", $panel)
        .accordion({
            collapsible: true,
            header: 'h3'
        });

        $(".opacity_slider", $panel)
            .slider({
                min: 0,
                max: 100,
                value: 50,
                change: Hybrid.Requery
            });

        $("input[type='checkbox']", $panel)
            .click(Hybrid.Requery);

        $("input[type='radio']", $panel)
            .click(Hybrid.Requery);

        $("#Draw6Earthquakes")
            .button()
            .click(Hybrid.Draw6Earthquakes);

        $("#Draw6Faults")
            .button()
            .click(Hybrid.Draw6Faults);

        // create map
        var mm = Microsoft.Maps;
        var mapOptions = {
            credentials: MainPage.credentials,
            center: new mm.Location(40, -105),
            mapTypeId: mm.MapTypeId.birdseye,
            zoom: 5,
            showScalebar: true,
            width: 300,
            height: 300
        };

        Hybrid.map = new mm.Map(document.getElementById("Map3"), mapOptions);
        $(window).resize(Hybrid.ResizeMap);

        // we have layers and items, and we handle them separately
        Hybrid.layerEntities = new mm.EntityCollection();
        Hybrid.map.entities.push(Hybrid.layerEntities);
        Hybrid.itemEntities = new mm.EntityCollection();
        Hybrid.map.entities.push(Hybrid.itemEntities);

        Hybrid.Show();

        // we track mouse movement for demonstration purposes
        mm.Events.addHandler(Hybrid.map, "mousemove", Hybrid.MouseMoved);

        // we update item data when the map moves
        mm.Events.addHandler(Hybrid.map, "viewchangeend", Hybrid.ViewChanged);
    },

    ViewChanged: function () {
        Hybrid.Requery();
    },

    // This is a map callback.
    // The callback argument is a Microsoft.Maps.MouseEventArgs
    MouseMoved: function (e) {
        var mm = Microsoft.Maps;
        var location = Hybrid.map.tryPixelToLocation(new mm.Point(e.pageX, e.pageY), mm.PixelReference.page);
        if (location == null || isNaN(location.latitude) || isNaN(location.longitude)) {
            return;
        }

        var $panel = $("#CurrentView3");
        $("#CurrentView3Latitude", $panel).text(location.latitude.toFixed(8));
        $("#CurrentView3Longitude", $panel).text(location.longitude.toFixed(8));
        $("#CurrentView3Zoom", $panel).text(Hybrid.map.getZoom().toFixed(0));
    },

    // For a given table name, make a TileLayer.
    MakeTileLayer: function (name, opacity) {
        var mm = Microsoft.Maps;

        // Create the tile layer source
        var tileSource = new mm.TileSource({
            uriConstructor: '/Tile/Get?layer=' + name + '&quadkey={quadkey}&thematic=false'
        });

        // Create the layer
        var layer = new mm.TileLayer({
            mercator: tileSource,
            opacity: opacity
        });
        return layer;
    },

    // Show only Earthquakes, set Tiling to 5, set Zoom to 6 over the West Coast.
    Draw6Earthquakes: function () {
        // uncheck all Show checkboxes except for Earthquakes
        $("#ShowItems3 input:checked").removeAttr("checked");
        $("#ShowItems3 input[name='Earthquakes']").attr("checked", "checked");

        $("#TilingDrawing input[value='5']").attr("checked", "checked");
        // move map to 40, -111, 5
        Hybrid.map.setView({
            animate: false,
            center: new Microsoft.Maps.Location(40, -111),
            zoom: 6
        });

        // update Zoom display to clue in the user
        $("#CurrentView3Zoom").text("6");
    },


    // Show only Faults, set Tiling to 5, set Zoom to 6 over the West Coast.
    Draw6Faults: function () {
        // uncheck all Show checkboxes except for Earthquakes
        $("#ShowItems3 input:checked").removeAttr("checked");
        $("#ShowItems3 input[name='Faults']").attr("checked", "checked");

        $("#TilingDrawing input[value='5']").attr("checked", "checked");
        // move map to 40, -111, 5
        Hybrid.map.setView({
            animate: false,
            center: new Microsoft.Maps.Location(40, -111),
            zoom: 6
        });

        // update Zoom display to clue in the user
        $("#CurrentView3Zoom").text("6");
    },

    // Reconfigure the displayed items.
    // Clear the display, add layers for low zoom levels, and query for data at high zoom levels.
    Requery: function () {
        Hybrid.ItemMouseout();

        var mm = Microsoft.Maps;
        var $panel = $("#ControlPanel3");

        // remove all layers from map
        Hybrid.itemEntities.clear();
        Hybrid.layerEntities.clear();

        var zoom = Hybrid.map.getZoom();
        var maxLayerZoom = parseInt($("input[type='radio'][name='TilingBoundary']:checked", $panel).val());

        // add back the selected layers
        // use the opacity from the associated slider
        // make CSV of tables that require querying
        var tables = [];
        $("#ShowItems3 input[type='checkbox']:checked", $panel)
            .each(function () {
                var name = $(this).attr("name");

                if (zoom > maxLayerZoom) {
                    tables.push(name);
                } else {
                    var opacity = $(this).closest(".item_row").find(".opacity_slider").slider("value");
                    opacity = parseFloat(opacity) / 100;
                    Hybrid.layerEntities.push(Hybrid.MakeTileLayer(name, opacity, false));
                }
            });

        if (tables.length == 0) {
            return;
        }
        // Send a query for item data
        // N.B. an alternative would be to send JSON

        // Get the bounding box of the map
        var view = Hybrid.map.getBounds();
        var query = Hybrid.MakeViewportQuery(tables, view);

        $.ajax({
            data: query,
            cache: false,
            success: Hybrid.ReceiveData,
            type: "POST",
            dataType: "json",
            url: "/Data/GetData"
        });
    },

    // jquery ajax completion
    // save data
    // alert on error
    // redraw data
    ReceiveData: function (data, status, xhr) {
        if (data.error) {
            alert(data.error);
            return;
        }

        if (!data["featureSet"]) {
            return;
        }
        Hybrid.DrawCountries(data.featureSet["Countries"]);
        Hybrid.DrawStates(data.featureSet["States"]);
        Hybrid.DrawCounties(data.featureSet["Counties"]);
        Hybrid.DrawFaults(data.featureSet["Faults"]);
        Hybrid.DrawEarthquakes(data.featureSet["Earthquakes"]);
    },

    // convenience function to get opacity value from a slider 
    GetOpacity: function (name) {
        var opacity = $("#ShowItems3 input[name='" + name + "']").closest(".item_row").find(".opacity_slider").slider("value");
        opacity = parseInt(opacity);
        if (opacity < 0)
            opacity = 0;
        else if (opacity > 255)
            opacity = 255;
        return opacity;
    },

    // Draw Countries.
    // Countries are drawn as filled polygons.
    // Bing Map SDK only draws simple polygons (no holes), so we only draw the exterior ring.
    // According to the GeoJSON standard, feature.geometry.coordinates is an array of polygons.
    DrawCountries: function (countries) {
        if (countries) {
            // get opacity from slider
            Hybrid.countryPolygonOptions.fillColor.a = Hybrid.GetOpacity("Countries");

            var mm = Microsoft.Maps;
            for (var i = 0; i < countries.features.length; i++) {
                var feature = countries.features[i];
                var geometry = feature.geometry;
                var properties = feature.properties;
                $.each(geometry.coordinates, function (index, poly) {
                    // draw only the first (exterior) polygon
                    var locations = [];
                    $.each(poly[0], function (cindex, coord) {
                        var location = new mm.Location(coord[0], coord[1]);
                        locations.push(location);
                    });

                    var polygon = new mm.Polygon(locations, Hybrid.countryPolygonOptions);

                    polygon["feature"] = feature;
                    mm.Events.addHandler(polygon, "mouseover", Hybrid.ItemMouseover);
                    mm.Events.addHandler(polygon, "mouseout", Hybrid.ItemMouseout);

                    Hybrid.itemEntities.push(polygon);
                });
            }
        }
    },


    // Draw Counties.
    // Counties are drawn as filled polygons.
    // Bing Map SDK only draws simple polygons (no holes), so we only draw the exterior ring.
    // According to the GeoJSON standard, feature.geometry.coordinates is an array of polygons.
    DrawCounties: function (counties) {
        if (counties) {
            // get opacity from slider
            Hybrid.countyPolygonOptions.fillColor.a = Hybrid.GetOpacity("Counties");

            var mm = Microsoft.Maps;
            for (var i = 0; i < counties.features.length; i++) {
                var feature = counties.features[i];
                var geometry = feature.geometry;
                var properties = feature.properties;
                $.each(geometry.coordinates, function (index, poly) {
                    // draw only the first (exterior) polygon
                    var locations = [];
                    $.each(poly[0], function (cindex, coord) {
                        var location = new mm.Location(coord[0], coord[1]);
                        locations.push(location);
                    });
                    var polygon = new mm.Polygon(locations, Hybrid.countyPolygonOptions);

                    polygon["feature"] = feature;
                    mm.Events.addHandler(polygon, "mouseover", Hybrid.ItemMouseover);
                    mm.Events.addHandler(polygon, "mouseout", Hybrid.ItemMouseout);

                    Hybrid.itemEntities.push(polygon);
                });
            }
        }
    },

    // Draw States.
    // States are drawn as filled polygons.
    // Bing Map SDK only draws simple polygons (no holes), so we only draw the exterior ring.
    // According to the GeoJSON standard, feature.geometry.coordinates is an array of polygons.
    DrawStates: function (states) {
        if (states) {
            // get opacity from slider
            Hybrid.statePolygonOptions.fillColor.a = Hybrid.GetOpacity("States");

            var mm = Microsoft.Maps;
            for (var i = 0; i < states.features.length; i++) {
                var feature = states.features[i];
                var geometry = feature.geometry;
                var properties = feature.properties;
                $.each(geometry.coordinates, function (index, poly) {
                    // draw only the first (exterior) polygon
                    var locations = [];
                    $.each(poly[0], function (cindex, coord) {
                        var location = new mm.Location(coord[0], coord[1]);
                        locations.push(location);
                    });
                    var polygon = new mm.Polygon(locations, Hybrid.statePolygonOptions);

                    polygon["feature"] = feature;
                    mm.Events.addHandler(polygon, "mouseover", Hybrid.ItemMouseover);
                    mm.Events.addHandler(polygon, "mouseout", Hybrid.ItemMouseout);

                    Hybrid.itemEntities.push(polygon);
                });
            }
        }
    },

    // Draw Earthquakes using pushpins.
    // According to the GeoJSON standard, feature.geometry.coordinates is an array [latitude, longitude].
    DrawEarthquakes: function (earthquakes) {
        if (earthquakes) {
            var mm = Microsoft.Maps;
            for (var i = 0; i < earthquakes.features.length; i++) {
                var feature = earthquakes.features[i];
                var geometry = feature.geometry;
                var properties = feature.properties;
                var location = new mm.Location(geometry.coordinates[0], geometry.coordinates[1]);
                var pp = new mm.Pushpin(location, Hybrid.earthquakePushpinOptions);

                pp["feature"] = feature;
                mm.Events.addHandler(pp, "mouseover", Hybrid.ItemMouseover);
                mm.Events.addHandler(pp, "mouseout", Hybrid.ItemMouseout);

                Hybrid.itemEntities.push(pp);
            }
        }
    },

    // Draw Faults as Polylines
    // According to the GeoJSON standard, feature.geometry.coordinates is an array lines
    DrawFaults: function (faults) {
        if (faults) {
            // get opacity from slider
            Hybrid.faultPolylineOptions.strokeColor.a = Hybrid.GetOpacity("Faults");

            var mm = Microsoft.Maps;
            for (var i = 0; i < faults.features.length; i++) {
                var feature = faults.features[i];
                var geometry = feature.geometry;
                var properties = feature.properties;
                $.each(geometry.coordinates, function (index, jline) {
                    var locations = [];
                    $.each(jline, function (lindex, coord) {
                        var location = new mm.Location(coord[0], coord[1]);
                        locations.push(location);
                    });
                    var line = new mm.Polyline(locations, Hybrid.faultPolylineOptions);

                    // add feature as expando data to the item for use by the mouseover callback
                    line["feature"] = feature;
                    mm.Events.addHandler(line, "mouseover", Hybrid.ItemMouseover);
                    mm.Events.addHandler(line, "mouseout", Hybrid.ItemMouseout);

                    Hybrid.itemEntities.push(line);
                });
            }
        }
    },

    // Show item properties when the mouse hovers over it.
    // 
    // This is a map callback.
    // The callback argument is a Microsoft.Maps.MouseEventArgs  
    ItemMouseover: function (mea) {
        var $props = $("#ItemProperties3");
        $("tbody tr", $props).remove();
        var properties = mea.target.feature.properties;
        $.each(properties, function (key, value) {
            var row = $('<tr><td>' + key + '</td><td>' + value + '</td></tr>');
            $("tbody", $props).append(row);
        });

        // calculate a position for the panel
        var loc = $("#MapPanel3").position();
        var top = mea.pageY + 10 - loc.top;
        var left = mea.pageX + 10 - loc.left;
        $props.css({ top: top, left: left });
        $props.show();
    },

    // Clear the properties display when the mouse leaves it.
    ItemMouseout: function () {
        var $props = $("#ItemProperties3");
        $props.hide();
    },

    // Create a query object using the current viewport and the tables
    MakeViewportQuery: function (tables, view) {
        var data = {
            "box.North": view.getNorth(),
            "box.South": view.getSouth(),
            "box.East": view.getEast(),
            "box.West": view.getWest()
        };
        $.each(tables, function (i, t) {
            data["tables[" + i + "]"] = t;
        });

        return data;
    },

    // this is called before initialize, so we bail if initialize has not been called
    Show: function () {
        if (Hybrid.map == null) {
            return;
        }

        $("#ControlPanel3").dialog("open");
        $("#Instructions3").dialog("open");

        Hybrid.ResizeMap();
    },

    ResizeMap: function () {
        if (Hybrid.map == null) {
            return;
        }
        if (MainPage.currentTabIndex != 3) {
            return;
        }

        // the available height is window height - container height + current map height
        // the container has set its width properly so we just use it
        var height = $(window).height() - $("body").height() + Hybrid.map.getHeight();
        Hybrid.map.setOptions({
            height: height,
            width: $("#MapPanel3").width()
        });
    },

    Unshow: function () {
        $("#Instructions3").dialog("close");
        $("#ControlPanel3").dialog("close");
        Hybrid.ItemMouseout();
    }
};

$(document).ready(MainPage.Initialize);

